package moonlit.chill.pay.service.impl.wechat;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.payments.model.TransactionAmount;
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
import com.wechat.pay.java.service.payments.nativepay.model.QueryOrderByOutTradeNoRequest;
import lombok.extern.slf4j.Slf4j;
import moonlit.chill.pay.cache.PayConfigDataCache;
import moonlit.chill.pay.constants.Constants;
import moonlit.chill.pay.constants.PayType;
import moonlit.chill.pay.service.PayStrategy;
import moonlit.chill.pay.util.WxConfigUtil;
import moonlit.chill.pay.vo.PayConfig;
import moonlit.chill.pay.vo.PayResult;
import moonlit.chill.pay.vo.PayResultForQuery;
import moonlit.chill.pay.vo.TradeParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Objects;

/**
 * @author MoonlitChill
 * @date 2024/4/16 11:46
 */
@Slf4j
@Service("wxQueryStrategy")
public class WxQueryStrategyServiceImpl implements PayStrategy {

    @Resource
    private PayConfigDataCache payConfigDataCache;

    @Autowired
    private WxConfigUtil wxConfigUtil;

    private static final String TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ssXXX";

    @Override
    public PayResult<?> payForPayQuery(TradeParam tradeParam) {
        log.info("微信支付查询参数：{}", JSONUtil.toJsonStr(tradeParam));
        PayResult<String> result = new PayResult<>();
        try {
            PayConfig payConfig = payConfigDataCache.getPayConfig();
            Config config = wxConfigUtil.getConfig(payConfig);
            NativePayService service = new NativePayService.Builder().config(config).build();
            QueryOrderByOutTradeNoRequest queryRequest = new QueryOrderByOutTradeNoRequest();
            queryRequest.setMchid(payConfig.getUId());
            queryRequest.setOutTradeNo(tradeParam.getTransNum());
            log.info("微信支付查询请求参数：{}", JSONUtil.toJsonStr(queryRequest));
            Transaction transaction = service.queryOrderByOutTradeNo(queryRequest);
            log.info("微信支付查询响应参数：{}", JSONUtil.toJsonStr(transaction));
            PayResultForQuery query = new PayResultForQuery();
            if (ObjectUtil.isNotEmpty(transaction)) {
                Transaction.TradeStateEnum state = transaction.getTradeState();
                query.setPayStatus(state.name());
                if (Objects.equals(state, Transaction.TradeStateEnum.SUCCESS)) {
                    query.setPayType(PayType.WX);
                    query.setPayTime(DateUtil.format(DateUtil.parse(transaction.getSuccessTime(), TIME_FORMAT), DatePattern.NORM_DATETIME_PATTERN));
                    query.setTransNum(transaction.getOutTradeNo());
                    query.setOutTradeNo(transaction.getTransactionId());
                    TransactionAmount amount = transaction.getAmount();
                    query.setPayAmount(new BigDecimal(amount.getTotal()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP));
                    query.setAddInfo(transaction.getAttach());
                    result.setSuccess(Boolean.TRUE);
                    result.setResult(JSONUtil.toJsonStr(query));
                } else if (state.equals(Transaction.TradeStateEnum.USERPAYING) || state.equals(Transaction.TradeStateEnum.NOTPAY)) {
                    result.error("用户尚未支付", Constants.PAY_USER_PAYING);
                } else if (state.equals(Transaction.TradeStateEnum.PAYERROR)) {
                    result.error("支付失败，请重新发起支付", Constants.PAY_FAIL_CODE);
                } else {
                    result.error("支付尚未成功", Constants.PAY_FAIL_CODE);
                }
            } else {
                result.error("查询失败，请重试", Constants.PAY_FAIL_CODE);
            }
        } catch (Exception e) {
            result.errorWithException(e.getMessage(), Constants.PAY_ERROR_CODE, e);
        }
        return result;
    }
}
